/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core.compiler;
import java.util.LinkedList;
import java.util.List;
import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.File;
import java.io.FileFilter;
import java.lang.ref.SoftReference;
import org.openide.compiler.DependencyException;
import org.openide.compiler.CompilationEngine;
import org.openide.compiler.CompilerTask;
import org.openide.compiler.CompilerGroup;
import org.openide.compiler.CompilerJob;
import org.openide.compiler.CompilerGroupException;
import org.openide.compiler.CompilerListener;
/** A class that makes compiling.
*
* @author Ales Novak
*/
public class CompilationEngineImpl extends CompilationEngine {
/** a queue
* @associates Object*/
private LinkedList queue;
/** a thread */
private CompilerThread t;
/** an event listener */
CompilerDisplayer displayer;
/** new CompilationEngineImpl */
public CompilationEngineImpl() {
queue = new LinkedList();
displayer = new CompilerDisplayer();
t = new CompilerThread(queue, displayer);
t.start();
}
/** Starts asynchronous compilation of a compiler job.
* @param job the job to compile
* @return the task object, one can wait for it to finish
* and obtain its results
*/
protected CompilerTask start(CompilerJob job) {
synchronized (queue) {
Object[] twins = new Object[2];
twins[0] = job;
CompilerTaskImpl task = new CompilerTaskImpl(job, this, twins);
twins[1] = task;
queue.addLast(twins);
queue.notify();
if (! t.isAlive()) {
(t = new CompilerThread(queue, displayer)).start();
} else {
Thread current = Thread.currentThread();
if (current.getClass() == CompilerThread.GroupCompiler.class) {
// deadlock avoidance
t.stopIt();
// new thr
(t = new CompilerThread(queue, displayer)).start();
}
}
return task;
}
}
// not API inherited methods - user must cast to this Class
/** Restarts compiler thread. */
public void stop() {
synchronized (queue) {
t.stopIt();
CompilerThread.GroupCompiler.interruptAll();
Iterator it = queue.iterator();
while (it.hasNext()) {
((CompilerTaskImpl) ((Object[]) it.next())[1]).done();
}
queue.clear();
queue.notify();
t = new CompilerThread(queue, displayer);
t.start();
}
}
/** @return <tt>true</tt> if compiling is executed */
public boolean isCompiling() {
return CompilerThread.GroupCompiler.all.size() > 0;
}
/** stops specified job */
void stopTask(CompilerTaskImpl job) {
synchronized (queue) {
if (queue.remove(job.ref)) {
return;
} else {
stop();
}
}
}
/** makes it public */
static List createLevels(CompilerJob job) throws DependencyException {
return createComputationLevels(job);
}
static Collection createGroups(Collection c) throws CompilerGroupException {
return createCompilerGroups(c);
}
/** A thread of control that compiles. */
protected static class CompilerThread extends Thread {
/** a queue */
public LinkedList queue;
/** an EventListener */
public CompilerDisplayer displayer;
/** stop flag */
private boolean stop;
/** current job */
public CompilerJob currentJob;
/** current task */
public CompilerTaskImpl currentTask;
/** new thread */
public CompilerThread(LinkedList queue, CompilerDisplayer displayer) {
setName("Compilation"); // NOI18N
setPriority(2);
setDaemon(true);
this.queue = queue;
this.displayer = displayer;
}
/** stops the thread */
public void stopIt() {
stop = true;
}
/** @return next CompilerJob from the queue */
private void nextJobAndTask() throws InterruptedException {
synchronized (queue) {
currentJob = null;
while (queue.size() == 0) {
queue.wait();
}
Object[] twins = (Object[]) queue.removeFirst();
currentJob = (CompilerJob) twins[0];
currentTask = (CompilerTaskImpl) twins[1];
}
}
/** a run method */
public void run() {
ListIterator iterator;
CompilerGroup[] groups;
GroupCompiler compiler;
boolean success;
for (;!stop;) {
try {
iterator = null;
groups = new CompilerGroup[0];
compiler = null;
nextJobAndTask(); // set currentTask and currentJob
displayer.compilationStarted(currentTask);
iterator = createLevels(currentJob).listIterator();
success = true;
while (iterator.hasNext() && success) { // through levels // if one level fails - stop it
groups = (CompilerGroup[]) createGroups((Collection) iterator.next()).toArray(groups);
// an array of groups - do parallel compilation
compiler = null;
for (int i = 0; i < groups.length; i++) {
if (groups[i] == null) break;
groups[i].addCompilerListener(displayer);
compiler = new GroupCompiler(groups[i], compiler);
}
if (compiler != null) { // is not upToDate
success &= compiler.stay(displayer); // wait for one level
}
}
currentTask.success = success;
} catch (ThreadDeath td) {
stop = true;
} catch (InterruptedException e) { // ignore
if (System.getProperty ("netbeans.debug.exceptions") != null) e.printStackTrace();
currentTask.success = false;
} catch (Throwable t) {
if (System.getProperty ("netbeans.debug.exceptions") != null) t.printStackTrace();
currentTask.success = false;
} finally {
if (currentTask != null) {
currentTask.done();
displayer.compilationFinished(currentTask);
}
currentJob = null;
currentTask = null;
iterator = null;
groups = null;
compiler = null;
}
}
}
/** Compiles CompilerGroup */
protected static class GroupCompiler extends Thread {
/**
* @associates GroupCompiler
*/
static Hashtable all = new Hashtable(11);
public CompilerGroup grp;
public GroupCompiler parent;
public boolean status;
public GroupCompiler(CompilerGroup grp, GroupCompiler parent) {
this.grp = grp;
this.parent = parent;
status = true; // OK
this.start();
}
/* called by compilation thread */
public boolean stay(CompilerListener listener) throws InterruptedException {
try {
all.put(this, this);
join();
grp.removeCompilerListener(listener);
if (parent != null) {
return parent.stay(listener) && status;
} else {
return status;
}
} finally {
all.remove(this);
}
}
public void run() {
try {
status = grp.start();
} catch (Throwable t) {
if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
t.printStackTrace();
}
status = false;
}
}
/** interrupts all groups threads */
static void interruptAll() {
Enumeration e = all.keys();
while (e.hasMoreElements()) {
Thread tt = (Thread) e.nextElement();
tt.interrupt();
}
}
}
}
}
/*
* Log
* 17 Gandalf 1.16 1/12/00 Ales Novak i18n
* 16 Gandalf 1.15 1/12/00 Ales Novak stopAction
* 15 Gandalf 1.14 12/23/99 Jaroslav Tulach
* 14 Gandalf 1.13 11/9/99 Ales Novak better report of
* exceptions
* 13 Gandalf 1.12 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 12 Gandalf 1.11 10/5/99 Ales Novak NullPointerException fix
* 11 Gandalf 1.10 10/1/99 Ales Novak major change of
* execution
* 10 Gandalf 1.9 7/24/99 Ian Formanek Printing stack trace on
* netbeans.debug.exceptions property only
* 9 Gandalf 1.8 7/21/99 Ales Novak deadlock
* 8 Gandalf 1.7 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 7 Gandalf 1.6 5/31/99 Jaroslav Tulach External Execution &
* Compilation
* 6 Gandalf 1.5 5/17/99 Ales Novak bugfix #1773
* 5 Gandalf 1.4 5/7/99 Ales Novak getAllLibraries moved to
* CompilationEngine
* 4 Gandalf 1.3 4/28/99 Ales Novak fixed changes from Task
* 3 Gandalf 1.2 4/23/99 Ales Novak compilation cancelled
* after one level fails
* 2 Gandalf 1.1 3/18/99 Jaroslav Tulach
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
*/